#include "stdafx.h"

#include <MyFC/Utility.h>
#include <MyFC/Control.h>

#include "mswin/winver.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

namespace My {

COLORREF MeanColor(COLORREF c1, COLORREF c2)
{
	return RGB(
		(GetRValue(c1) + GetRValue(c2)) / 2,
		(GetGValue(c1) + GetGValue(c2)) / 2,
		(GetBValue(c1) + GetBValue(c2)) / 2		
	);
}

COLORREF MeanSysColor(int c1, int c2)
{
	return MeanColor(::GetSysColor(c1), ::GetSysColor(c2));
}

CRect AlignRect(const CRect & r0, CRect r, int align)
{
	int dx = 0, dy = 0;

	switch (align & ALIGN_HMASK) {
	case ALIGN_HLEFT:
		dx = r0.left - r.left;
		break;
	case ALIGN_HRIGHT:
		dx = r0.right - r.right;
		break;
	case ALIGN_HCENTER:
		dx = (r0.left + r0.right - r.left - r.right) / 2;
		break;
	}
	switch (align & ALIGN_VMASK) {
	case ALIGN_VTOP:
		dy = r0.top - r.top;
		break;
	case ALIGN_VBOTTOM:
		dy = r0.bottom - r.bottom;
		break;
	case ALIGN_VCENTER:
		dy = (r0.top + r0.bottom - r.top - r.bottom) / 2;
		break;
	}
	r.OffsetRect(dx, dy);
	return r;
}

CRect AlignRect(const CRect & r, const CPoint & p, int align)
{
	int w = r.Width(), h = r.Height(), x = r.left, y = r.top;

	switch (align & ALIGN_HMASK) {
	case ALIGN_HLEFT:
		x = p.x;
		break;
	case ALIGN_HRIGHT:
		x = p.x - w;
		break;
	case ALIGN_HCENTER:
		x = p.x - w / 2;
		break;
	}
	switch (align & ALIGN_VMASK) {
	case ALIGN_VTOP:
		y = p.y;
		break;
	case ALIGN_VBOTTOM:
		y = p.y - h;
		break;
	case ALIGN_VCENTER:
		y = p.y - h / 2;
		break;
	}
	return CRect(x, y, x + w, y + h);
}


SaveObjects::SaveObjects(CDC * pDC) 
{
	m_pDC = pDC;
	m_pPen = pDC->GetCurrentPen();
	m_pBrush = pDC->GetCurrentBrush();
	m_pFont = pDC->GetCurrentFont();
}

SaveObjects::~SaveObjects()	
{
	m_pDC->SelectObject(m_pPen);
	m_pDC->SelectObject(m_pBrush);
	m_pDC->SelectObject(m_pFont);
}

ClientDC::ClientDC(Control * pControl)
	: CClientDC(pControl->GetWindow()) 
{ 
	m_Org = SetWindowOrg(- pControl->GetWindowOffset());
}

ClientDC::~ClientDC()
{
	SetWindowOrg(m_Org);
}

ClipRect::ClipRect(Control * pOwner, CDC * pDC, const CRect & rect, bool enabled)
{
	if (enabled) {
		m_pDC = pDC;
		m_Old.CreateRectRgn(0, 0, 0, 0);
		if (::GetClipRgn(m_pDC->m_hDC, (HRGN)m_Old.m_hObject) == 0)
			m_Old.DeleteObject();
		CRgn rgn;
		rgn.CreateRectRgnIndirect(&rect);
		rgn.OffsetRgn(pOwner->GetWindowOffset());
		if (m_Old.m_hObject != 0)
			m_pDC->SelectClipRgn(&rgn, RGN_AND);
		else
			m_pDC->SelectClipRgn(&rgn);
	} else
		m_pDC = 0;
}

ClipRect::~ClipRect()
{
	if (m_pDC != 0) {
		if (m_Old.m_hObject != 0)
			m_pDC->SelectClipRgn(&m_Old);
		else 
			m_pDC->SelectClipRgn(0);
	}
}

void Draw3dRect(CDC * pDC, const CRect & r, COLORREF cTL, COLORREF cBR)
{
	SaveObjects save(pDC);
	CPen pTL(PS_SOLID, 1, cTL);
	CPen pBR(PS_SOLID, 1, cBR);
	CPen pMean(PS_SOLID, 1, MeanColor(cTL, cBR));

	pDC->SelectObject(&pTL);
	pDC->MoveTo(r.left, r.bottom - 1);
	pDC->LineTo(r.left, r.top);
	pDC->LineTo(r.right - 1, r.top);

	pDC->SelectObject(&pBR);
	pDC->MoveTo(r.right - 1, r.top + 1);
	pDC->LineTo(r.right - 1, r.bottom - 1);
	pDC->LineTo(r.left, r.bottom - 1);

	pDC->SelectObject(&pMean);
	pDC->MoveTo(r.left, r.bottom - 1);
	pDC->LineTo(r.left, r.bottom);
	pDC->MoveTo(r.right - 1, r.top);
	pDC->LineTo(r.right - 1, r.top + 1);
}

void DrawAlternateHorizLine(CDC * pDC, int y, int x1, int x2, COLORREF c)
{
	if (x1 > x2)
		std::swap(x1, x2);
	if (mswin::is_winNT()) {
		LOGBRUSH lBrush;
		lBrush.lbStyle = BS_SOLID;
		lBrush.lbColor = c;
		lBrush.lbHatch = 0;
		CPen pDots(PS_COSMETIC|PS_ALTERNATE, 1, &lBrush);
		pDC->SelectObject(&pDots);
		pDC->MoveTo(x1, y);
		pDC->LineTo(x2, y);	
	}
	else {
		//pen style PS_ALTERNATE is not supported by Windows 9x family
		while (x1 < x2) {
			VERIFY(pDC->SetPixelV(x1, y, c));
			x1 += 2;
		}
	}
}

void XorAlternateVertLine(CDC * pDC, int x, int y1, int y2, COLORREF c)
{
	if (y1 > y2)
		std::swap(y1, y2);
	if (mswin::is_winNT()) {
		LOGBRUSH lb;
		lb.lbColor = c;
		lb.lbStyle = BS_SOLID;
		lb.lbHatch = 0;

		CPen pDots(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
		pDC->SelectObject(&pDots);

		int mode = pDC->SetROP2(R2_XORPEN);

		pDC->MoveTo(x, y1);
		pDC->LineTo(x, y2);

		pDC->SetROP2(mode);
	}
	else {
		//pen style PS_ALTERNATE is not supported by Windows 9x family
		while (y1 < y2) {
			COLORREF u = pDC->GetPixel(x, y1);
			VERIFY(pDC->SetPixelV(x, y1, c^u));
			y1 += 2;
		}
	}
}

} // My
